﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using ArgusLight.Fractals2D;

namespace Fractals
{
	class PreviewManager
	{
		Fractal fractal;
		Fractal fractal2;
		FractalParameter para2;
		BitmapSource previewImage;
		DispatcherTimer timer;

		public event RoutedPropertyChangedEventHandler<BitmapSource> PreviewImageChanged;

		public PreviewManager()
		{
			this.timer = new DispatcherTimer();
			this.timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
			this.timer.Tick += (a, b) =>
				{
					this.timer.Stop();
				};
			this.IsFinished = false;
			this.IsEnabled = true;
		}

		public BitmapSource PreviewImage
		{
			get { return this.previewImage; }
			set
			{
				if (value != this.previewImage)
				{
					if (this.PreviewImageChanged != null)
						this.PreviewImageChanged(this, new RoutedPropertyChangedEventArgs<BitmapSource>(this.previewImage, value));
					this.previewImage = value;
				}
			}
		}
		public bool IsFinished { get; private set; }
		public bool IsEnabled { get; set; }
		public Fractal Fractal
		{ 
			get 
			{
				if (this.fractal2 != null)
					return this.fractal2;
				return this.fractal; 
			} 
		}

		public void StartCalculation(Type FractalType, Type ColoringType, FractalParameter para, ColoringParameter cPara)
		{
			if (this.IsEnabled == false)
				return;
			this.previewImage = new WriteableBitmap(para.PixelWidth, para.PixelHeight);
			this.IsFinished = false;
			if (this.fractal == null || this.fractal.IsCalculating == false)
			{
				this.fractal = this.CreateFractalInstance(FractalType, ColoringType, cPara);
				this.fractal.StartCalculation(para);
			}
			else
			{
				this.fractal2 = this.CreateFractalInstance(FractalType, ColoringType, cPara);
				this.para2 = para;
				this.fractal.RequestCalculationCancelation();
			}
		}

		public void AbortAll()
		{
			this.fractal2 = null;
			this.para2 = null;
			if (this.fractal != null)
				this.fractal.RequestCalculationCancelation();
		}

		Fractal CreateFractalInstance(Type FractalType, Type ColoringType, ColoringParameter cPara)
		{
			Fractal f = (Fractal)Activator.CreateInstance(FractalType);
			f.SetColoring((Coloring)Activator.CreateInstance(ColoringType));
			f.Coloring.Parameter = cPara;
			f.ProgressUpdated += fractal_ProgressUpdated;
			f.CalculationAborted += fractal_CalculationAborted;
			f.CalculationFinished += fractal_CalculationFinished;
			return f;
		}

		void fractal_CalculationFinished(object sender, CalculationFinishedArgs e)
		{
			if (this.fractal2 != null)
				return;
			this.PreviewImage = this.fractal.GetImage();
			this.IsFinished = true;
		}

		void fractal_CalculationAborted(object sender, CalculationAbortedArgs e)
		{
			if (this.fractal2 != null)
			{
				this.fractal = this.fractal2;
				this.fractal2 = null;
				this.fractal.StartCalculation(this.para2);
				this.para2 = null;
			}
		}

		void fractal_ProgressUpdated(object sender, ProgressUpdatedArgs e)
		{
			if (this.timer.IsEnabled == true)
				return;
			this.PreviewImage = this.fractal.GetImage().MakeTransparent(Colors.Black);
			this.timer.Start();
		}
	}
}
